 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.wizards.datatransfer;

 import java.io.File ;
 import java.io.FileFilter ;
 import java.lang.reflect.InvocationTargetException ;

 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectDescription;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IResourceStatus;
 import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.SubProgressMonitor;
 import org.eclipse.jface.dialogs.ErrorDialog;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.wizard.WizardPage;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.DirectoryDialog;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.actions.WorkspaceModifyOperation;
 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
 import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
 import org.eclipse.ui.internal.wizards.datatransfer.DataTransferMessages;

 /**
  * Standard main page for a wizard that creates a project resource from
  * whose location already contains a project.
  * <p>
  * This page may be used by clients as-is; it may be also be subclassed to suit.
  * </p>
  * <p>
  * Example usage:
  * <pre>
  * mainPage = new WizardExternalProjectImportPage("basicNewProjectPage");
  * mainPage.setTitle("Project");
  * mainPage.setDescription("Create a new project resource.");
  * </pre>
  * </p>
  */
 public class WizardExternalProjectImportPage extends WizardPage {

     private FileFilter projectFilter = new FileFilter () {
         //Only accept those files that are .project
 public boolean accept(File pathName) {
             return pathName.getName().equals(
                     IProjectDescription.DESCRIPTION_FILE_NAME);
         }
     };

     //Keep track of the directory that we browsed to last time
 //the wizard was invoked.
 private static String previouslyBrowsedDirectory = ""; //$NON-NLS-1$

     // widgets
 private Text projectNameField;

     private Text locationPathField;

     private Button browseButton;

     private IProjectDescription description;

     private Listener locationModifyListener = new Listener() {
         public void handleEvent(Event e) {
             setPageComplete(validatePage());
         }
     };

     // constants
 private static final int SIZING_TEXT_FIELD_WIDTH = 250;

     /**
      * Creates a new project creation wizard page.
      *
      */
     public WizardExternalProjectImportPage() {
         super("wizardExternalProjectPage"); //$NON-NLS-1$
 setPageComplete(false);
         setTitle(DataTransferMessages.WizardExternalProjectImportPage_title);
         setDescription(DataTransferMessages.WizardExternalProjectImportPage_description);

     }

     /** (non-Javadoc)
      * Method declared on IDialogPage.
      */
     public void createControl(Composite parent) {

         initializeDialogUnits(parent);

         Composite composite = new Composite(parent, SWT.NULL);

         PlatformUI.getWorkbench().getHelpSystem().setHelp(composite,
                 IIDEHelpContextIds.NEW_PROJECT_WIZARD_PAGE);

         composite.setLayout(new GridLayout());
         composite.setLayoutData(new GridData(GridData.FILL_BOTH));
         composite.setFont(parent.getFont());

         createProjectNameGroup(composite);
         createProjectLocationGroup(composite);
         validatePage();
         // Show description on opening
 setErrorMessage(null);
         setMessage(null);
         setControl(composite);
     }

     /**
      * Creates the project location specification controls.
      *
      * @param parent the parent composite
      */
     private final void createProjectLocationGroup(Composite parent) {

         // project specification group
 Composite projectGroup = new Composite(parent, SWT.NONE);
         GridLayout layout = new GridLayout();
         layout.numColumns = 3;
         projectGroup.setLayout(layout);
         projectGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
         projectGroup.setFont(parent.getFont());

         // new project label
 Label projectContentsLabel = new Label(projectGroup, SWT.NONE);
         projectContentsLabel.setText(DataTransferMessages.WizardExternalProjectImportPage_projectContentsLabel);
         projectContentsLabel.setFont(parent.getFont());

         createUserSpecifiedProjectLocationGroup(projectGroup);
     }

     /**
      * Creates the project name specification controls.
      *
      * @param parent the parent composite
      */
     private final void createProjectNameGroup(Composite parent) {

         Font dialogFont = parent.getFont();

         // project specification group
 Composite projectGroup = new Composite(parent, SWT.NONE);
         GridLayout layout = new GridLayout();
         layout.numColumns = 2;
         projectGroup.setFont(dialogFont);
         projectGroup.setLayout(layout);
         projectGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

         // new project label
 Label projectLabel = new Label(projectGroup, SWT.NONE);
         projectLabel.setText(DataTransferMessages.WizardExternalProjectImportPage_nameLabel);
         projectLabel.setFont(dialogFont);

         // new project name entry field
 projectNameField = new Text(projectGroup, SWT.BORDER | SWT.READ_ONLY);
         GridData data = new GridData(GridData.FILL_HORIZONTAL);
         data.widthHint = SIZING_TEXT_FIELD_WIDTH;
         projectNameField.setLayoutData(data);
         projectNameField.setFont(dialogFont);
         projectNameField.setBackground(parent.getDisplay().getSystemColor(
                 SWT.COLOR_WIDGET_BACKGROUND));
     }

     /**
      * Creates the project location specification controls.
      *
      * @param projectGroup the parent composite
      */
     private void createUserSpecifiedProjectLocationGroup(Composite projectGroup) {

         Font dialogFont = projectGroup.getFont();

         // project location entry field
 this.locationPathField = new Text(projectGroup, SWT.BORDER);
         GridData data = new GridData(GridData.FILL_HORIZONTAL);
         data.widthHint = SIZING_TEXT_FIELD_WIDTH;
         this.locationPathField.setLayoutData(data);
         this.locationPathField.setFont(dialogFont);

         // browse button
 this.browseButton = new Button(projectGroup, SWT.PUSH);
         this.browseButton.setText(DataTransferMessages.DataTransfer_browse);
         this.browseButton.setFont(dialogFont);
         setButtonLayoutData(this.browseButton);

         this.browseButton.addSelectionListener(new SelectionAdapter() {
             public void widgetSelected(SelectionEvent event) {
                 handleLocationBrowseButtonPressed();
             }
         });

         locationPathField.addListener(SWT.Modify, locationModifyListener);
     }

     /**
      * Returns the current project location path as entered by
      * the user, or its anticipated initial value.
      *
      * @return the project location path, its anticipated initial value, or <code>null</code>
      * if no project location path is known
      */
     public IPath getLocationPath() {

         return new Path(getProjectLocationFieldValue());
     }

     /**
      * Creates a project resource handle for the current project name field value.
      * <p>
      * This method does not create the project resource; this is the responsibility
      * of <code>IProject::create</code> invoked by the new project resource wizard.
      * </p>
      *
      * @return the new project resource handle
      */
     public IProject getProjectHandle() {
         return ResourcesPlugin.getWorkspace().getRoot().getProject(
                 getProjectName());
     }

     /**
      * Returns the current project name as entered by the user, or its anticipated
      * initial value.
      *
      * @return the project name, its anticipated initial value, or <code>null</code>
      * if no project name is known
      */
     public String getProjectName() {
         return getProjectNameFieldValue();
     }

     /**
      * Returns the value of the project name field
      * with leading and trailing spaces removed.
      *
      * @return the project name in the field
      */
     private String getProjectNameFieldValue() {
         if (projectNameField == null) {
             return ""; //$NON-NLS-1$
 }

         return projectNameField.getText().trim();
     }

     /**
      * Returns the value of the project location field
      * with leading and trailing spaces removed.
      *
      * @return the project location directory in the field
      */
     private String getProjectLocationFieldValue() {
         return locationPathField.getText().trim();
     }

     /**
      * Open an appropriate directory browser
      */
     private void handleLocationBrowseButtonPressed() {
         DirectoryDialog dialog = new DirectoryDialog(locationPathField
                 .getShell());
         dialog.setMessage(DataTransferMessages.WizardExternalProjectImportPage_directoryLabel);

         String dirName = getProjectLocationFieldValue();
         if (dirName.length() == 0) {
             dirName = previouslyBrowsedDirectory;
         }

         if (dirName.length() == 0) {
             dialog.setFilterPath(getWorkspace().getRoot().getLocation()
                     .toOSString());
         } else {
             File path = new File (dirName);
             if (path.exists()) {
                 dialog.setFilterPath(new Path(dirName).toOSString());
             }
         }

         String selectedDirectory = dialog.open();
         if (selectedDirectory != null) {
             previouslyBrowsedDirectory = selectedDirectory;
             locationPathField.setText(previouslyBrowsedDirectory);
             setProjectName(projectFile(previouslyBrowsedDirectory));
         }
     }

     /**
      * Returns whether this page's controls currently all contain valid
      * values.
      *
      * @return <code>true</code> if all controls are valid, and
      * <code>false</code> if at least one is invalid
      */
     private boolean validatePage() {

         String locationFieldContents = getProjectLocationFieldValue();

         if (locationFieldContents.equals("")) { //$NON-NLS-1$
 setErrorMessage(null);
             setMessage(DataTransferMessages.WizardExternalProjectImportPage_projectLocationEmpty);
             return false;
         }

         IPath path = new Path(""); //$NON-NLS-1$
 if (!path.isValidPath(locationFieldContents)) {
             setErrorMessage(DataTransferMessages.WizardExternalProjectImportPage_locationError);
             return false;
         }

         File projectFile = projectFile(locationFieldContents);
         if (projectFile == null) {
             setErrorMessage(NLS.bind(DataTransferMessages.WizardExternalProjectImportPage_notAProject, locationFieldContents));
             return false;
         }
         setProjectName(projectFile);

         if (getProjectHandle().exists()) {
             setErrorMessage(DataTransferMessages.WizardExternalProjectImportPage_projectExistsMessage);
             return false;
         }

         setErrorMessage(null);
         setMessage(null);
         return true;
     }

     private IWorkspace getWorkspace() {
         IWorkspace workspace = IDEWorkbenchPlugin.getPluginWorkspace();
         return workspace;
     }

     /**
      * Return whether or not the specifed location is a prefix
      * of the root.
      */
     private boolean isPrefixOfRoot(IPath locationPath) {
         return Platform.getLocation().isPrefixOf(locationPath);
     }

     /**
      * Set the project name using either the name of the
      * parent of the file or the name entry in the xml for
      * the file
      */
     private void setProjectName(File projectFile) {

         //If there is no file or the user has already specified forget it
 if (projectFile == null) {
             return;
         }

         IPath path = new Path(projectFile.getPath());

         IProjectDescription newDescription = null;

         try {
             newDescription = getWorkspace().loadProjectDescription(path);
         } catch (CoreException exception) {
             //no good couldn't get the name
 }

         if (newDescription == null) {
             this.description = null;
             this.projectNameField.setText(""); //$NON-NLS-1$
 } else {
             this.description = newDescription;
             this.projectNameField.setText(this.description.getName());
         }
     }

     /**
      * Return a.project file from the specified location.
      * If there isn't one return null.
      */
     private File projectFile(String locationFieldContents) {
         File directory = new File (locationFieldContents);
         if (directory.isFile()) {
             return null;
         }

         File [] files = directory.listFiles(this.projectFilter);
         if (files != null && files.length == 1) {
             return files[0];
         }

         return null;
     }

     /**
      * Creates a new project resource with the selected name.
      * <p>
      * In normal usage, this method is invoked after the user has pressed Finish on
      * the wizard; the enablement of the Finish button implies that all controls
      * on the pages currently contain valid values.
      * </p>
      *
      * @return the created project resource, or <code>null</code> if the project
      * was not created
      */
     IProject createExistingProject() {

         String projectName = projectNameField.getText();
         final IWorkspace workspace = ResourcesPlugin.getWorkspace();
         final IProject project = workspace.getRoot().getProject(projectName);
         if (this.description == null) {
             this.description = workspace.newProjectDescription(projectName);
             IPath locationPath = getLocationPath();
             //If it is under the root use the default location
 if (isPrefixOfRoot(locationPath)) {
                 this.description.setLocation(null);
             } else {
                 this.description.setLocation(locationPath);
             }
         } else {
             this.description.setName(projectName);
         }

         // create the new project operation
 WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
             protected void execute(IProgressMonitor monitor)
                     throws CoreException {
                 monitor.beginTask("", 2000); //$NON-NLS-1$
 project.create(description, new SubProgressMonitor(monitor,
                         1000));
                 if (monitor.isCanceled()) {
                     throw new OperationCanceledException();
                 }
                 project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 1000));

             }
         };

         // run the new project creation operation
 try {
             getContainer().run(true, true, op);
         } catch (InterruptedException e) {
             return null;
         } catch (InvocationTargetException e) {
             // ie.- one of the steps resulted in a core exception
 Throwable t = e.getTargetException();
             if (t instanceof CoreException) {
                 if (((CoreException) t).getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
                     MessageDialog
                             .openError(
                                     getShell(),
                                     DataTransferMessages.WizardExternalProjectImportPage_errorMessage,
                                     NLS.bind(
                                             DataTransferMessages.WizardExternalProjectImportPage_caseVariantExistsError,
                                             projectName)
                             );
                 } else {
                     ErrorDialog
                             .openError(
                                     getShell(),
                                     DataTransferMessages.WizardExternalProjectImportPage_errorMessage,
                                     null, ((CoreException) t).getStatus());
                 }
             }
             return null;
         }

         return project;
     }

     /*
      * see @DialogPage.setVisible(boolean)
      */
     public void setVisible(boolean visible) {
         super.setVisible(visible);
         if (visible) {
             this.locationPathField.setFocus();
         }
     }

 }

